﻿using System;
using System.Globalization;
using System.Linq;
using System.Web.Security;
using System.Web.UI.WebControls;
using Altairis.FluffyCloud.Data;
using Altairis.FluffyCloud.Security;
using Altairis.Web;

namespace Altairis.FluffyCloud.WebCore.Pages.Account {

    public partial class Registration : System.Web.UI.Page {

        protected void BirthDateValidator_ServerValidate(object source, ServerValidateEventArgs args) {
            var stringVal = args.Value;
            DateTime dateVal;
            if (string.IsNullOrWhiteSpace(stringVal)) {
                // Empty input is always valid
                args.IsValid = true;
            }
            else if (!DateTime.TryParseExact(stringVal, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateVal)) {
                // Invalid format
                args.IsValid = false;
            }
            else {
                // Value sanity check
                args.IsValid = dateVal >= DateTime.Today.AddYears(-100) && dateVal <= DateTime.Today.AddYears(-10);
            }
        }

        protected void ButtonSubmitStep1_Click(object sender, EventArgs e) {
            if (!this.IsValid) return;

            var email = this.EmailTextBox.Text;
            var existingUserName = Membership.GetUserNameByEmail(email);
            if (!string.IsNullOrEmpty(existingUserName)) {
                // E-mail already used
                this.MultiViewPage.SetActiveView(this.ViewError);
                this.LiteralErrorDuplicateEmail.Text = string.Format(this.LiteralErrorDuplicateEmail.Text, email, existingUserName);
                this.LiteralErrorDuplicateEmail.Visible = true;
            }
            else {
                // Build confirmation URI
                var uri = new UriBuilder(this.Request.ApplicationBaseUri());
                var code = SignedToken.CreateSignedToken(email);
                uri.Path = string.Format("/reg/{0}/{1}", email, code);

                // Send mail
                Altairis.MailToolkit.Mailer.SendTemplatedMessage(
                    email,                  // recipient
                    "EmailVerification",    // template
                    uri.ToString());        // {0}

                // Display message
                this.MultiViewPage.SetActiveView(this.ViewStep2);
                this.LiteralVerify.Text = string.Format(this.LiteralVerify.Text, email);
            }
        }

        protected void ButtonSubmitStep3_Click(object sender, EventArgs e) {
            if (!this.IsValid) return;

            // Try to create user
            MembershipCreateStatus status;
            var u = Membership.CreateUser(
                this.UserNameTextBox.Text.ToLower(),
                this.PasswordTextBox.Text,
                this.RouteData.Values["email"] as string,
                null, // pw question
                null, // pw answer
                true, // is approved
                out status);

            if (status == MembershipCreateStatus.Success) {
                // Created successfully
                using (var dc = new FluffyDbContext()) {
                    var user = dc.Users.Single(x => x.UserName.Equals(u.UserName));

                    // Set user options
                    user.Species = this.SpeciesTextBox.Text;
                    user.Comment = this.CommentTextBox.Text;
                    user.Description = this.DescriptionTextBox.Text;
                    user.RegistrationIpAddress = this.Request.UserHostAddress;

                    // Set birth date
                    DateTime birthDate;
                    if (DateTime.TryParseExact(this.BirthDateTextBox.Text, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out birthDate)) user.BirthDate = birthDate;

                    // Set security code
                    var code = new byte[32];
                    using (var rng = new System.Security.Cryptography.RNGCryptoServiceProvider()) {
                        rng.GetBytes(code);
                    }
                    user.SecurityCode = Altairis.Web.Convert.ToUrlSafeBase64String(code, true);

                    // Add user to default role
                    var allUsersRole = dc.Roles.Single(x => x.RoleName.Equals(Role.EveryoneRoleName));
                    user.Roles.Add(allUsersRole);

                    // Add minors and unspecified to minors role
                    var minorThreshold = DateTime.Today.AddYears(-18);
                    if (!user.BirthDate.HasValue || user.BirthDate.Value > minorThreshold) user.Roles.Add(dc.Roles.Single(x => x.RoleName.Equals(Role.MinorsRoleName)));

                    // Setup default ACL
                    dc.UserAclEntries.Add(new UserAclEntry { UserName = u.UserName, Operation = UserAclEntry.OperationSendPrivateMessage, Role = allUsersRole, Action = true });
                    dc.UserAclEntries.Add(new UserAclEntry { UserName = u.UserName, Operation = UserAclEntry.OperationReadProfilePersonal, Role = allUsersRole, Action = true });
                    dc.UserAclEntries.Add(new UserAclEntry { UserName = u.UserName, Operation = UserAclEntry.OperationReadProfileContacts, Role = allUsersRole, Action = true });

                    // Save changes
                    dc.SaveChanges();
                }
                this.MultiViewPage.SetActiveView(this.ViewStep4);
            }
            else if (status == MembershipCreateStatus.DuplicateUserName) {
                // Duplicate user name
                this.MultiViewPage.SetActiveView(this.ViewError);
                this.LiteralErrorDuplicateUserName.Text = string.Format(this.LiteralErrorDuplicateUserName.Text, this.UserNameTextBox.Text);
                this.LiteralErrorDuplicateUserName.Visible = true;
            }
            else {
                // Other error
                this.MultiViewPage.SetActiveView(this.ViewError);
                this.LiteralErrorOther.Text = string.Format(this.LiteralErrorOther.Text, status);
                this.LiteralErrorOther.Visible = true;
            }
        }

        protected void ButtonSubmitStep4_Click(object sender, EventArgs e) {
            this.Response.RedirectToRoute("MyProfile");
        }

        protected void Page_Load(object sender, EventArgs e) {
            // Get verification data
            var email = this.RouteData.Values["email"] as string;
            var code = this.RouteData.Values["code"] as string;

            if (!string.IsNullOrEmpty(code) && !string.IsNullOrEmpty(email)) {
                // Check if there is already user with this address
                var existingUserName = Membership.GetUserNameByEmail(email);
                if (!string.IsNullOrEmpty(existingUserName)) {
                    // E-mail already used
                    this.MultiViewPage.SetActiveView(this.ViewError);
                    this.LiteralErrorDuplicateEmail.Text = string.Format(this.LiteralErrorDuplicateEmail.Text, email, existingUserName);
                    this.LiteralErrorDuplicateEmail.Visible = true;
                    return;
                }

                // Verification code was supplied - check it
                if (!code.Equals(SignedToken.CreateSignedToken(email))) {
                    // Invalid code
                    this.MultiViewPage.SetActiveView(this.ViewError);
                    this.LiteralErrorCodeInvalid.Text = string.Format(this.LiteralErrorCodeInvalid.Text, email);
                    this.LiteralErrorCodeInvalid.Visible = true;
                    return;
                }

                // Verification code is valid - show registration form for Step 3
                this.MultiViewPage.SetActiveView(this.ViewStep3);
                this.LiteralVerified.Text = string.Format(this.LiteralVerified.Text, email);
                this.PreviewGravatar.EmailAddress = email;
            }
        }
    }
}